package com.fs.console.base.interceptor;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.fs.common.pojo.Company;
import com.fs.console.base.annotation.PassToken;
import com.fs.console.base.enums.CodeEnum;
import com.fs.console.base.execption.ExecptionData;
import com.fs.console.base.utils.DateUtils;
import com.fs.console.base.vo.LoginUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author ACE
 * @desc 拦截器去获取token并验证token
 * @creationTime 2019-03-07 11:24
 * @projectName gps-root
 * @packageName com.fs.mobile.interceptor
 */
public class AuthenticationInterceptor implements HandlerInterceptor {

    //存储token以及过期时间
    public static Map<String,String> map = new HashMap<>();
    //存储userId以及登录信息
    public static Map<String, LoginUser> loginUserMap = new HashMap<>();
    //存储userId所对应的部门信息
    public static Map<String, List<Company>> userCompanyMap = new HashMap<>();

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
        String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
        if(StringUtils.isBlank(token)){
            token = httpServletRequest.getParameter("token");//从 http 请求头中获取失败在尝试从参数中获取 token
        }
        // 如果不是映射到方法直接通过  || "/error".equals(httpServletRequest.getRequestURI())
        if (!(object instanceof HandlerMethod)) {
            return true; 
        }
        HandlerMethod handlerMethod = (HandlerMethod) object;
        Method method = handlerMethod.getMethod();
        //检查是否有passtoken注释，有则跳过认证
        if (method.isAnnotationPresent(PassToken.class)) {
            PassToken passToken = method.getAnnotation(PassToken.class);
            if (passToken.required()) {
                return true;
            }
        }
        //检查有没有需要用户权限的注解,必须登录才能请求通过
        // 执行认证
        if (token == null) {
            throw new ExecptionData(CodeEnum.EX101);
        }

        //判断token是否存在和过期
        String date = map.get(token);
        if(StringUtils.isBlank(date)){
            throw new ExecptionData(CodeEnum.EX101);
        }else{
            Date startDate = DateUtils.parseDate(date, DateUtils.DEFAULT_PATTERN);
            if ((new Date().getTime() - startDate.getTime()) > (60 * 60 * 1000)){
                /*map.remove(token);
                throw new ExecptionData(CodeEnum.EX101);*/
                map.put(token, DateUtils.curDate());
            }else{
                map.put(token, DateUtils.curDate());
            }
        }

        // 获取 token 中的 user id
        String userId;
        try {
            userId = JWT.decode(token).getAudience().get(0);
        } catch (JWTDecodeException j) {
            throw new ExecptionData(CodeEnum.EX101);
        }
        LoginUser user = loginUserMap.get(userId);
        if (user == null) {
            throw new ExecptionData(CodeEnum.EX101);
        }
        // 验证 token
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getUser().getPwd())).build();
        try {
            jwtVerifier.verify(token);
        } catch (JWTVerificationException e) {
            throw new ExecptionData(CodeEnum.EX101);
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest,
                           HttpServletResponse httpServletResponse,
                           Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest,
                                HttpServletResponse httpServletResponse,
                                Object o, Exception e) throws Exception {
    }
}